import time
import datetime
import os
from quant_researcher.quant.project_tool.localize import DATA_DIR
from quant_researcher.quant.project_tool.wrapper_tools.common_wrappers import deco_retry
from quant_researcher.quant.project_tool.time_tool import str_to_timestamp
from dateutil.tz import *
import pandas as pd
import requests
import json
from logger import logger
import os
import traceback
from task_monitor import task_to_db, send_error_to_email


history_url = 'https://history.deribit.com/api/v2'
base_url = 'https://www.deribit.com/api/v2'


@deco_retry(retry=5, retry_sleep=15)
def get_instrument(instrument_name='BTC-13JAN23-16000-P'):
    """
    获取某个instrument基本信息

    :param instrument_name:
    :return:
    """

    url = f'{history_url}/public/get_instrument?instrument_name={instrument_name}'
    res = requests.get(url)
    res = json.loads(res.text)['result']
    return res


@deco_retry(retry=5, retry_sleep=15)
def get_instruments(currency='BTC', kind='option', this_datetime=''):
    """

    :param currency: 支持BTC, ETH, USDC
    :param kind: 支持future, option, spot, future_combo, option_combo
    :return:
    """

    # 获取已经过期的instrument
    url = f'{history_url}/public/get_instruments?currency={currency}&kind={kind}&expired=true'
    res1 = requests.get(url)
    res1 = pd.DataFrame(json.loads(res1.text)['result'])
    res1.sort_values(by=['expiration_timestamp', 'instrument_name'], inplace=True)

    # 获取尚在交易中的instrument
    url = f'{history_url}/public/get_instruments?currency={currency}&kind={kind}'
    res2 = requests.get(url)
    res2 = pd.DataFrame(json.loads(res2.text)['result'])
    res2.sort_values(by=['expiration_timestamp', 'instrument_name'], inplace=True)

    data = pd.concat([res1, res2], ignore_index=True)
    data.drop_duplicates(subset=['instrument_name'], ignore_index=True, inplace=True)

    timezone = '+0000'
    data['expiration_datetime'] = pd.to_datetime(data['expiration_timestamp'], unit='ms').dt.tz_localize('UTC').dt.tz_convert(timezone)
    data['expiration_datetime'] = data['expiration_datetime'].dt.strftime('%Y-%m-%d %H:%M:%S')
    data['creation_datetime'] = pd.to_datetime(data['creation_timestamp'], unit='ms').dt.tz_localize('UTC').dt.tz_convert(timezone)
    data['creation_datetime'] = data['creation_datetime'].dt.strftime('%Y-%m-%d %H:%M:%S')

    if this_datetime:
        data = data[(data['expiration_datetime'] > this_datetime) & (data['creation_datetime'] < this_datetime)]

    return data


@deco_retry(retry=5, retry_sleep=15)
def get_last_trades_by_currency(currency='BTC', kind='option'):
    """

    :param currency: 支持BTC, ETH, USDC
    :param kind: 支持future, option, spot, future_combo, option_combo
    :return:
    """

    url = f'{base_url}/public/get_last_trades_by_currency?currency={currency}&kind={kind}&include_old=true'
    res = requests.get(url)
    res = pd.DataFrame(json.loads(res.text)['result'])
    # res.sort_values(by='instrument_id', inplace=True)
    res.sort_values(by=['expiration_timestamp', 'instrument_name'], inplace=True)

    return res


@deco_retry(retry=5, retry_sleep=15)
def get_last_trades_by_currency_and_time(currency='BTC', kind='option'):
    """

    :param currency: 支持BTC, ETH, USDC
    :param kind: 支持future, option, spot, future_combo, option_combo
    :return:
    """

    url = f'{base_url}/public/get_last_trades_by_currency_and_time?currency={currency}&kind={kind}&end_timestamp=1590480022768&start_timestamp=1590470022768&include_old=true'
    res1 = requests.get(url)
    res1 = pd.DataFrame(json.loads(res1.text)['result'])
    # res.sort_values(by='instrument_id', inplace=True)
    res1.sort_values(by=['expiration_timestamp', 'instrument_name'], inplace=True)

    return res1


@deco_retry(retry=1000, retry_sleep=60)
def get_last_trades_by_instrument(instrument_name='BTC-27OCT23-27500-C', count=50):
    """

    :param instrument_name: 'BTC-27OCT23-27500-C', 'BTC-15FEB19-4000-P'
    :param count: 返回多少笔交易,最大值不超过10000
    :return:
    """

    all_data_df_list = []

    # url = f'{base_url}/public/get_last_trades_by_instrument?instrument_name={instrument_name}&count={count}'  # 默认返回该instrument_name最近count笔交易【注意如果instrument已到期则无法获取，必须通过下面链接】
    url = f'{history_url}/public/get_last_trades_by_instrument?instrument_name={instrument_name}&count={count}&include_old=true'
    res = requests.get(url)
    if '{"reason":"wrong format","param":"instrument_name"}' in res.text:
        print(f'{instrument_name}"reason":"wrong format","param":"instrument_name"')
        return None
    data = pd.DataFrame(json.loads(res.text)['result']['trades'])
    if data.empty:
        print(f'{instrument_name}无交易记录')
        return None

    data.sort_values(by=['trade_seq'], ascending=False, inplace=True)
    data = reformat_timestamp(data)
    all_data_df_list.append(data)

    has_more_flag = json.loads(res.text)['result']['has_more']
    while has_more_flag:
        end_seq = min(data['trade_seq'])
        url = f'{history_url}/public/get_last_trades_by_instrument?instrument_name={instrument_name}&end_seq={end_seq}&count={count}&include_old=true'
        res = requests.get(url)
        data = pd.DataFrame(json.loads(res.text)['result']['trades'])
        if data.empty:
            print(f'{instrument_name}无交易记录')
            has_more_flag = False
        else:
            data.sort_values(by=['trade_seq'], ascending=False, inplace=True)
            data = reformat_timestamp(data)
            all_data_df_list.append(data)
            has_more_flag = json.loads(res.text)['result']['has_more']

    all_data = pd.concat(all_data_df_list)
    all_data.drop_duplicates(subset=['trade_seq'], inplace=True)

    return all_data


@deco_retry(retry=5, retry_sleep=15)
def get_last_trades_by_instrument_and_time(instrument_name='BTC-27OCT23-27500-C', count=50, start_datetime='', end_datetime='2023-10-18 00:00:00'):
    """

    :param instrument_name: 'BTC-27OCT23-27500-C', 'BTC-15FEB19-4000-P'
    :param count: 返回多少笔交易,最大值不超过10000
    :return:
    """

    end_timestamp = str_to_timestamp(end_datetime, fmt='%Y-%m-%d %H:%M:%S', tz_str='+0000') * 1000
    if start_datetime:
        start_timestamp = str_to_timestamp(start_datetime, fmt='%Y-%m-%d %H:%M:%S', tz_str='+0000') * 1000
    else:
        start_timestamp = end_timestamp - 60 * 60 * 1000

    url = f'{history_url}/public/get_last_trades_by_instrument_and_time?instrument_name={instrument_name}&count={count}&end_timestamp={end_timestamp}&start_timestamp={start_timestamp}'
    res1 = requests.get(url)
    if '{"reason":"wrong format","param":"instrument_name"}' in res1.text:
        print(f'{instrument_name}"reason":"wrong format","param":"instrument_name"')
        return None

    res1 = pd.DataFrame(json.loads(res1.text)['result']['trades'])
    if res1.empty:
        print(f'{instrument_name}无交易记录')
        return None

    res1.sort_values(by=['trade_seq'], ascending=False, inplace=True)
    data = reformat_timestamp(res1)

    return data


@deco_retry(retry=5, retry_sleep=15)
def get_mark_price_history(instrument_name='BTC-27OCT23-27500-C', start_datetime='2023-10-01 08:00:00', end_datetime='2023-10-18 07:15:00'):
    """

    :param instrument_name: 'BTC-27OCT23-27500-C', 'BTC-15FEB19-4000-P'
    :param count: 返回多少笔交易,最大值不超过10000
    :return:
    """

    start_timestamp = str_to_timestamp(start_datetime, fmt='%Y-%m-%d %H:%M:%S', tz_str='+0000') * 1000
    end_timestamp = str_to_timestamp(end_datetime, fmt='%Y-%m-%d %H:%M:%S', tz_str='+0000') * 1000

    url = f'{base_url}/public/get_mark_price_history?instrument_name={instrument_name}&start_timestamp={start_timestamp}&end_timestamp={end_timestamp}'
    res1 = requests.get(url)
    res1 = pd.DataFrame(json.loads(res1.text)['result']['trades'])
    res1.sort_values(by=['trade_seq'], ascending=False, inplace=True)

    data = reformat_timestamp(res1)

    return data


def get_all_historical_trade_data(the_datetime='2021-01-01 00:00:00', update=True):
    # 获取所有instrument的交易数据
    file_path = os.path.join(DATA_DIR, 'deribit_historical_trade_data')
    all_instrument_info = get_instruments(currency='BTC', kind='option')
    all_instrument_info = all_instrument_info[all_instrument_info['expiration_datetime'] >= the_datetime]
    # all_instrument_info = ['BTC-31DEC21-80000-C', 'BTC-31DEC21-100000-C', 'BTC-25JUN21-32000-P']
    for instrument_name in all_instrument_info['instrument_name']:
        # for instrument_name in all_instrument_info:
        file_name = os.path.join(file_path, f'{instrument_name}')

        if update:
            df = get_last_trades_by_instrument(instrument_name=instrument_name, count=10000)
            if df is not None:
                df.to_excel(f'{file_name}.xlsx')
        else:
            if not os.path.exists(f'{file_name}.xlsx'):
                df = get_last_trades_by_instrument(instrument_name=instrument_name, count=10000)
                if df is not None:
                    df.to_excel(f'{file_name}.xlsx')
            else:
                print(f'{instrument_name}交易数据已存在，不用重新获取')


def reformat_timestamp(df):
    data = df.copy()
    timezone = '+0000'
    data['datetime'] = pd.to_datetime(data['timestamp'], unit='ms').dt.tz_localize('UTC').dt.tz_convert(timezone)
    data['datetime'] = data['datetime'].dt.strftime('%Y-%m-%d %H:%M:%S')
    data.set_index('datetime', inplace=True)

    return data


if __name__ == '__main__':
    from quant_researcher.quant.project_tool.time_tool import get_yesterday
    endtime = get_yesterday(marker='with_n_dash')
    endtime += " 00:00:00"
    logger.info("开始get_all_historical_trade_data")
    task_to_db(os.path.basename(__file__), 'get_all_historical_trade_data')
    try:
        get_all_historical_trade_data(the_datetime=endtime, update=True)
    except Exception as e:
        msg = traceback.format_exc()
        logger.info(msg)
        send_error_to_email(script_name=os.path.basename(__file__), func_name="get_all_historical_trade_data", message=msg)
        raise e
    task_to_db(os.path.basename(__file__), 'get_all_historical_trade_data', 1)
    logger.info("成功get_all_historical_trade_data")
    # df = get_last_trades_by_instrument(instrument_name='BTC-31DEC21-80000-C', count=10000)
    # df = get_last_trades_by_instrument(instrument_name='BTC-8NOV22-17000-P', count=10000)
    # df = get_last_trades_by_instrument_and_time(instrument_name='BTC-27OCT23-27500-C', count=10000)
    # df = get_mark_price_history(instrument_name='BTC-27OCT23-27500-C', start_datetime='2023-10-01 08:00:00', end_datetime='2023-10-18 00:00:00')

    # # 获取某个时间点附近不同行权价的期权交易数据
    # for this_datetime in ['2022-11-08 00:00:00', '2021-05-15 00:00:00', '2020-03-12 00:00:00']:
    #     # df = get_instruments(currency='BTC', kind='option', this_datetime=this_datetime)
    #     file_path = os.path.join(DATA_DIR)
    #     file_name = os.path.join(file_path, f'deribit_all_instrument_{this_datetime[:10]}')
    #     # df.to_excel(f'{file_name}.xlsx')
    #
    #     df = pd.read_excel(f'{file_name}.xlsx')
    #     df = df[df['option_type'] == 'put']
    #     df['settlement_date'] = [i.split('-')[1] for i in df['instrument_name']]
    #     settlement_date_list = list(df['settlement_date'].unique())
    #
    #     if this_datetime == '2022-11-08 00:00:00':
    #         this_price = 20000
    #     elif this_datetime == '2021-05-15 00:00:00':
    #         this_price = 50000
    #     elif this_datetime == '2020-03-12 00:00:00':
    #         this_price = 8000
    #     # strike_price_list = [this_price + i for i in [-4000, -3000, -2000, -1000, 0, 1000, 2000, 3000, 4000]]
    #     strike_price_list = [this_price + i for i in [-1000, 0, 1000]]
    #
    #     all_instrument_name = []
    #     for settlement_date in settlement_date_list:
    #         for strike_price in strike_price_list:
    #             all_instrument_name.append(f'BTC-{settlement_date}-{strike_price}-P')
    #
    #     all_result_list = []
    #     for instrument_name in all_instrument_name:
    #         df = get_last_trades_by_instrument(instrument_name=instrument_name, count=10000)
    #         if df is not None:
    #             result = abs(df['timestamp'] - str_to_timestamp(this_datetime, fmt='%Y-%m-%d %H:%M:%S', tz_str='+0000') * 1000)
    #             the_index = result.idxmin()
    #             result = df.loc[the_index, :]
    #             if isinstance(result, pd.Series):
    #                 result = pd.DataFrame(result).T
    #             else:
    #                 result = pd.DataFrame(result.iloc[0, :]).T
    #             all_result_list.append(result)
    #         time.sleep(3)
    #
    #     all_result_df = pd.concat(all_result_list, axis=0)
    #
    #     file_name = os.path.join(file_path, f'deribit_all_instrument_trade_info_{this_datetime[:10]}')
    #     all_result_df.to_excel(f'{file_name}.xlsx')
